#ifndef SWE_FRICTION_HPP
#define SWE_FRICTION_HPP

#include "sweSolver.hpp"

namespace hms
{

template<typename _SolverType>
class SourceFieldCallable : public CrtpBase<_SolverType>
{
public:
	using SolverType = _SolverType; // visible to the outside
	using SourceFieldName = typename SolverType::SourceFieldName;

protected:
	std::experimental::observer_ptr<const SolverType> m_solver {nullptr};

public:
	SourceFieldCallable( const SolverBase<SolverType>& solverArg ){
		solver( solverArg );
	}

	const SolverType& solver() const {
		assert( m_solver && "Dereferencing nullptr!" );
		return *m_solver;
	}
	void solver( const SolverBase<SolverType>& solverArg ){
		m_solver = std::experimental::make_observer( &(solverArg.derived()) );
	}

	static constexpr SourceFieldName fieldName(){
		this->fieldNameImp();
	}

	ArrayXXs operator() (){
		return this->compute();
	}
};

template<typename MeshType>
class SweFriction : public SourceFieldCallable<SWESolver<MeshType>>
{
public:
	using SolverType = SWESolver<MeshType>;
	using BaseType = SourceFieldCallable<SolverType>;
	using SourceFieldName = typename SolverType::SourceFieldName;

private:

public:
	SweFriction() = default;

	SweFriction( const SWESolver<MeshType>& solverArg ) :
		BaseType(solverArg)
	{}

	ArrayXXs operator() (){
		/* dummy */
		ArrayXXs vals;
		resizeFieldValues(
			vals, 1, this->solver().mesh(), Uniformity::NonUniform
		);

		vals = 0;

		return vals;
	}

	static constexpr fieldNameImp(){
		return SourceFieldName::Friction;
	}
};

template<typename Callable, Uniformity isUniform, typename SolverType>
void setCallable( SolverBase<SolverType>& solver ){
	auto fieldName { Callable::fieldName() };
	if ( solver.useSourceField(fieldName) ){
		Callable c { solver };
		using MeshType = typename SolverBase<SolverType>::MeshType;
		SourceField<isUniform, MeshType> field {
			solver.mesh(), std::move(c)
		};
		field.updateValues();
		solver.sourceField(fieldName) = std::move(field);
	}
}

template<typename MeshType>
void setFrictionCallable( SWESolver<MeshType>& solver ){
	setCallable<SweFriction<MeshType>, NonUniform>(solver)
}

} // namespace hms

#endif